package com.quick.develop.flowable.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.quick.develop.flowable.constant.BpmConstants;
import com.quick.develop.flowable.enums.BpmExecuteCmd;
import com.quick.develop.flowable.enums.BpmTaskCategory;
import com.quick.develop.flowable.utils.BpmTaskUtil;
import com.quick.develop.framework.utils.StringUtils;
import com.quick.develop.flowable.application.IBpmRuleApplication;
import com.quick.develop.flowable.application.IBpmTaskAssigneeApplication;
import com.quick.develop.flowable.domain.rule.BpmProcessRule;
import com.quick.develop.flowable.framework.cmd.RecordTaskInfoChangeCmd;
import com.quick.develop.flowable.framework.enums.definition.BpmTaskAssignRuleTypeEnum;
import com.quick.develop.flowable.framework.factory.FlowServiceFactory;
import com.quick.develop.flowable.service.definition.IBpmProcessDefinitionService;
import com.quick.develop.flowable.service.task.IBpmTaskService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * @author junyuan.liu
 * @description:  任务创建的时候，分配任务处理人 先考虑单个处理人和候选人
 *                  后续需要考虑:
 *                          子流程情况
 *                          任务是否退回、查找代办人为上次处理的人？？
 *
 * @date 2022/5/25 13:29
 */
@Component(value = "taskAssignee")
@Slf4j
public class TaskAssigneeListener extends FlowServiceFactory implements TaskListener {
    private static final long serialVersionUID = 4615758117161877857L;
    @Resource
    private IBpmProcessDefinitionService bpmProcessDefinitionService;

    @Resource
    private IBpmRuleApplication bpmRuleApplication;

    @Resource
    private IBpmTaskAssigneeApplication bpmTaskAssigneeApplication;

    @Resource
    private IBpmTaskService bpmTaskService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void notify(DelegateTask delegateTask) {
        Map<String, Object> variables = delegateTask.getVariables();
        String processInstanceId = delegateTask.getProcessInstanceId();
        String taskId = delegateTask.getId();
        //设置撤回人、 退回人是否设置为上次任务完成的最后一个人？？
        Optional.ofNullable(variables).ifPresent(vars -> {
            if (vars.containsKey(BpmConstants.EXECUTE_CMD) ) {
                String executeCmd = vars.get(BpmConstants.EXECUTE_CMD).toString();
                // 撤回
                if (BpmExecuteCmd.WITHDRAW.cmd.equals(executeCmd) && vars.containsKey(BpmConstants.WITHDRAW_USER)) {
                    taskService.setAssignee(taskId, vars.get(BpmConstants.WITHDRAW_USER).toString());
                }
                // 退回 查询当前节点任务完成的最后一个人
                else if(BpmExecuteCmd.BACK.cmd.equals(executeCmd)) {
                    String assignee = bpmTaskService.getSingleBackAssignee(processInstanceId, delegateTask.getTaskDefinitionKey());
                    Optional.ofNullable(assignee).ifPresent(u -> taskService.setAssignee(taskId, u));
                }
            }
        });

        //如果处理人为空 则进行覆盖
        if (StrUtil.isEmpty(delegateTask.getAssignee()) ){
           ProcessDefinition processDefinition = bpmProcessDefinitionService
                   .getProcessDefinition(delegateTask.getProcessDefinitionId());
            String modelKey = processDefinition.getKey();
            //获取规则
            BpmProcessRule rule = bpmRuleApplication.getTaskRule(modelKey, delegateTask.getTaskDefinitionKey());

            //候选 或者指定 预设值逻辑和指定类似
            if (Objects.equals(BpmTaskAssignRuleTypeEnum.CANDIDATE.getType() ,rule.getAssigneeType()) ) {
                
                delegateTask.addCandidateGroups(rule.getOptions());
                //设置候选组标识
                delegateTask.setDescription(BpmTaskUtil.concatDescription(delegateTask.getDescription(),BpmTaskCategory.CANDIDATE.getCode()));
                managementService.executeCommand(new RecordTaskInfoChangeCmd(taskId));
            } else {
                //设置处理人 要用api设置 要不然历史数据还要考虑手动设置
                taskService.setAssignee(taskId, getAssignee(delegateTask, rule));
            } 
        }

    }

    private String getAssignee(DelegateTask delegateTask, BpmProcessRule rule){
        String user = "admin";
        try {
            Set<String> users = bpmTaskAssigneeApplication.calculateTaskCandidateUsers(delegateTask.getProcessInstanceId() ,rule, delegateTask);
            user = Optional.ofNullable(users).map(u -> {
                if (!u.isEmpty()) {
                    return CollUtil.get(u, 0);
                }else {
                    log.warn("{}任务找不到处理人，默认赋值admin", delegateTask.getId());
                    return "admin";
                }
            }).orElse("admin");
        } catch (Exception e) {
            log.error("{}任务处理人查询异常，默认赋值admin，{}",  delegateTask.getId(), e.getMessage());
            e.printStackTrace();
        }
        return user;
    }
    
    private void setCandidateFlag(DelegateTask delegateTask) {
        String description = delegateTask.getDescription();
        if (StringUtils.isNotEmpty(description) ) {
            if (!description.contains(BpmTaskCategory.CANDIDATE.getCode())) {
                description = description + BpmConstants.COMMENT_SEPARATOR + BpmTaskCategory.CANDIDATE.getCode();
                delegateTask.setDescription(description);
            }
        }else {
            delegateTask.setDescription(BpmTaskCategory.CANDIDATE.getCode());
        }
    }

    private void addGroups(String taskId, Set<String> groups){
        if (groups.isEmpty()) {
            return;
        }
        groups.forEach(g -> {
            taskService.addCandidateGroup(taskId, g);
        });
    }

}
